Multithreading and multiprocessing are two different software execution models that are used to achieve concurrent processing. With multithreading, all of the threads in a program share a single copy of memory so any change made to memory by one thread is visible to all of the other threads. With multiprocessing, each process is provided with a private copy of the program's memory so that any change made by a process is visible only to the process that made the change. Multithreading is more memory efficient since there is only one copy of the program's memory regardless of the number of threads, but multithreading requires software to be designed for thread-safety. Many legacy software programs are not designed to be thread-safe, so the multiprocessing model is often used instead. However, this doesn't allow for the efficient memory use provided by multithreading.
In order to reduce memory usage in multiprocessing programs, some operating systems, such as Linux®, use a memory management optimization technique referred to as copy-on-write. With copy-on-write, sub-processes initially share parent process memory with no private memory, in a manner similar to multithreading. Memory is copied into the sub-process' private memory space only when the sub-process writes to memory. The more that a sub-process writes to memory, the more memory it uses. Multiprocessing programs are often designed to access memory in a read-only manner to minimize copy-on-writes. A common pattern is for an initial parent process to load or create common data and then initiate sub-processes which access this data in a read-only manner.
Certain programming languages implement a memory management process referred to as “garbage collection” that tracks memory usage and deallocates unused memory. Other programming languages implement a data type referred to as a smart pointer. Smart pointers automatically deallocate memory when it is no longer used, to free the programmer from having to manage memory manually. Smart pointers typically do this by maintaining a counter that tracks the number of independent references to memory. The reference count is incremented each time the program accesses the memory that the pointer manages and decremented when the access completes. When the reference count reaches zero in such implementations, the smart pointer deallocates the memory.
Operating systems, such as Linux®, are designed in a way that cause multiprocessing programs to use significantly less memory if they mostly read from memory and rarely write to memory. However, this is problematic in multiprocessing programs that use reference counting smart pointers. This is because smart pointers cause every access of the memory that is managed by the smart pointer to modify the reference count even if the memory is only being accessed for reading. Changing the reference count causes a copy-on-write into the sub-process' private memory. This copy-on-write operation causes inefficient use of memory in some multiprocessing programs that use smart pointers. What is needed is a system for and a method of minimizing the copy-on-write operations while still providing a method of managing memory usage.